/*
 * ﻿Copyright (C) 2012-2013 NewMain Softech
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package for_beanshell_in_ant_file;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.Calendar;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;

import org.apache.maven.project.MavenProject;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.Exit;
import org.apache.tools.ant.types.FileSet;
import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
import org.sonatype.plexus.components.cipher.PlexusCipher;

/**
 * This class is just code holder, in order to take advantage of IDE's content assist and 
 * other features for coding beanshell script being used in ant file of this project.
 * The code here better be only ones demanded before Maven's test phase (so no need to say why not being 
 * able to move to source folder.) If code will be used in Maven's test phase or later phase, then such 
 * code should be moved to test source folder and beanshell script in ant file should refer the yielded 
 * class file(s) in the test output directory. <br />  
 * Coding note: Beanshell does not handle Generic and Annotation.
 * 
 * @author <a href="mailto:artymt@gmail.com">Arata Y.</a>
 */
public class ForBeanshell {
	Project project;
	Task self;
	
	private void set_auxiliary_Maven_properties_target_script() throws Throwable {
		self.log( 
				String.format(
					"START %1$s TASK of %2$s TARGET >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
		
	    MavenProject mavenProject 
		= (MavenProject)(self.getProject().getReference( "maven.project"));
		Properties mavenProperties = mavenProject.getProperties();
		
	    // Define project.license.years Maven property to interprete 
	    // referece in header.txt for maven-license-plugin. ------------
		String propertyKey = "project.license.years";
		if ( mavenProperties.getProperty( propertyKey) == null) {
			String propertyValue = mavenProject.getInceptionYear();
				Calendar calendar = Calendar.getInstance();
				String thisYear 
				= String.valueOf( calendar.get( Calendar.YEAR));
				if ( mavenProject.getInceptionYear() == null) {
					propertyValue = thisYear;
				}
				else {
					if ( !thisYear.equals( propertyValue)) {
						propertyValue = propertyValue + "-" + thisYear;
					}
				}
			
			mavenProperties.setProperty( propertyKey, propertyValue);
				self.log(
					String.format(
						"Set %2$s value to %1$s Maven property.",
						new Object[]{ 
							propertyKey, 
							((propertyValue.length() < 1) 
								? "empty string (\"\")" : ("\"" + propertyValue + "\"")) 
							}
						) 
					);
		}
	    // -------------------------------------------------------------
		
		self.log( 
				String.format(
					"END %1$s TASK of %2$s TARGET <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
	}
	
	Project project;
	Task self;
	
	/**
	 * Define javadoc.dir property what points 
	 * ${project.build.directory}${file.separator}..${file.separator}javadoc. 
	 * Used at beanshell script of update-javadoc-target Ant target in maven-antrun.ant.xml Ant file. 
	 * Keeping this in {@link ForBeanshell} class simply because there is not appropriate test class  
	 * to store and I don't like to create new test class just to hold the content of this method. 
	 * 
	 * @throws Exception
	 */
	public void defineJavadocDirProperty() throws Exception {
		self.log( 
				String.format(
					"START %1$s TASK of %2$s TARGET >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
		
		final Hashtable propertyHashtable = project.getProperties();
			// Better not to use project.getProperty. When it returns null and assigned to variable, 
			// beanshell does not recognize it as null in regular Java way. Also, there seems 
			// to be problem of handing over object loaded by different class loader.
		
		final String projectBuildDirPropertyName = "project.build.directory";
		final String projectBuildDirStr = propertyHashtable.get( projectBuildDirPropertyName).toString();
		final File projectBuildDir = new File( projectBuildDirStr);
			if ( !projectBuildDir.isDirectory()) {
				throw new BuildException( 
						String.format(
								"%1$s property has not been defined.",
								new Object[]{
										projectBuildDirPropertyName
										}
								)
						);
			}
		final String javadocDirName = "javadoc";
		File javadocDir = new File( projectBuildDir.getParentFile(), javadocDirName);
			if ( !javadocDir.exists()) javadocDir.mkdirs();
		final String javadocDirPropertyName = "javadoc.dir";
		project.setProperty( javadocDirPropertyName, javadocDir.getAbsoluteFile().getCanonicalPath());	
		
		self.log( 
				String.format(
					"END %1$s TASK of %2$s TARGET <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
	}
	
	/**
	 * Show files in ${project.build.directory}${file.separator}apidocs different from one in 
	 * ${project.build.directory}${file.separator}javadoc. 
	 * Used at beanshell script of update-javadoc-target Ant target in maven-antrun.ant.xml Ant file. 
	 * Keeping this in {@link ForBeanshell} class simply because there is not appropriate test class  
	 * to store and I don't like to create new test class just to hold the content of this method. 
	 * 
	 * @throws Exception
	 */
	public void showJavadocDiff() throws Exception {
		self.log( 
				String.format(
					"START %1$s TASK of %2$s TARGET >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);

		FileSet fileSet = (FileSet)(project.getReference( "diff_fileset"));
		if ( fileSet.size() < 1) {
			self.log(
					String.format(
						"No differences of JavaDoc files between %1$s and %2$s.",
						new Object[]{ 
							project.getProperty( "project.build.directory")
							.concat( project.getProperty( "file.separator")).concat( "apidocs"),
							project.getProperty( "project.build.directory")
							.concat( project.getProperty( "file.separator")).concat( "javadoc")
							}
						)
					);
		}
		else {
			self.log(
				String.format(
					"Different JavaDoc files in %1$s from ones in %2$s:",
					new Object[]{ 
						project.getProperty( "project.build.directory")
						.concat( project.getProperty( "file.separator")).concat( "apidocs"),
						project.getProperty( "project.build.directory")
						.concat( project.getProperty( "file.separator")).concat( "javadoc")
						}
					)
				);
			Iterator iterator = fileSet.iterator();
			while( iterator.hasNext()) {
				self.log( iterator.next());
			} // while
		}
		
		self.log( 
				String.format(
					"END %1$s TASK of %2$s TARGET <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
	}
	
	private void test_mvnservercreden_task_encrypt_test_target_script() throws Throwable {
		final String passwordPropName = "mvnservercreden_encryp_test.password";
		final String encryptedPassword = project.getProperty( passwordPropName);
		PlexusCipher plexusCipher = new DefaultPlexusCipher();
		final String masterPassword = "MasterPasswordForTest";
		final String decryptedPassword 
		= plexusCipher.decryptDecorated( encryptedPassword, masterPassword);
		final String rawPassword = "VYqcdI,.e--tCfq0ah`LGCZBYy*D!69A";
		if ( !rawPassword.equals( decryptedPassword)) {
			throw new BuildException(
					String.format(
							"Encrypted password by mvnservercreden Ant task did not match with original " 
							+ "raw password after decrypting it by %1$s class:" 
							+ "%n%2$cOriginal raw password: %3$s"
							+ "%n%2$cEncrypted and decorated password: %4$s"
							+ "%n%2$cDecrypted password: %5$s",
							new Object[]{ 
									DefaultPlexusCipher.class.getSimpleName(),
									'\t', 
									rawPassword, 
									encryptedPassword, 
									decryptedPassword}
							)
					);
		}
		
	    final MavenProject mavenProject 
		= (MavenProject)(self.getProject().getReference( "maven.project"));
		final Properties mavenProperties = mavenProject.getProperties();
		final String encryptedPasswordInMavenProperty = mavenProperties.getProperty( passwordPropName);
		if ( !encryptedPassword.equals( encryptedPasswordInMavenProperty)) {
			throw new BuildException(
					String.format(
							"mvnservercreden Ant task stored different encoded password to each of " 
							+ "%1$s Maven property and %1$s Ant property: " 
							+ "%n%2$c%1$s Maven property value : %3$s"
							+ "%n%2$c%1$s Ant property value : %4$s",
							new Object[]{ 
									passwordPropName, 
									'\t', 
									encryptedPasswordInMavenProperty,
									encryptedPassword
									}
							)
					);
		}
	}
}
